package 中等.模拟;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 你需要设计一个包含验证码的验证系统。每一次验证中，用户会收到一个新的验证码，
 * 这个验证码在 currentTime 时刻之后 timeToLive 秒过期。如果验证码被更新了，
 * 那么它会在 currentTime （可能与之前的 currentTime 不同）时刻延长 timeToLive 秒。
 * 请你实现 AuthenticationManager 类：
 * AuthenticationManager(int timeToLive) 构造 AuthenticationManager 并设
 * 置 timeToLive 参数。
 * generate(string tokenId, int currentTime) 给定 tokenId ，在当前时间 
 * currentTime 生成一个新的验证码。
 * renew(string tokenId, int currentTime) 将给定 tokenId 且 未过期 的验证码
 * 在 currentTime 时刻更新。如果给定 tokenId 对应的验证码不存在或已过期，请你
 * 忽略该操作，不会有任何更新操作发生。
 * countUnexpiredTokens(int currentTime) 请返回在给定 currentTime 时刻，未过
 * 期 的验证码数目。
 * 如果一个验证码在时刻 t 过期，且另一个操作恰好在时刻 t 发生（renew 或者 
 * countUnexpiredTokens 操作），过期事件 优先于 其他操作。
 * <p>
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode.cn/problems/design-authentication-manager
 */
public class 设计一个验证系统_1797 {

    public static void main(String[] args) {

        AuthenticationManager manager = new AuthenticationManager(1);

        manager.renew("ajvy", 1);
        manager.countUnexpiredTokens(1);
        manager.countUnexpiredTokens(6);
        manager.countUnexpiredTokens(6);

    }

    /**
     * 哈希表
     * 每个 tokenId 都记录最晚过期时间
     * 注意：记录的最晚过期时间那一秒是已经过期的！！！
     */
    static class AuthenticationManager {

        private int liveTime;

        private Map<String, Integer> map = new HashMap<>();

        public AuthenticationManager(int timeToLive) {
            liveTime = timeToLive;
        }

        public void generate(String tokenId, int currentTime) {
            map.put(tokenId, currentTime + liveTime);
        }

        public void renew(String tokenId, int currentTime) {
            if (!map.containsKey(tokenId) || currentTime >= map.get(tokenId)) {
                map.remove(tokenId);
                return;
            }
            map.put(tokenId, currentTime + liveTime);
        }

        public int countUnexpiredTokens(int currentTime) {
            int count = 0;

            Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Integer> entry = iterator.next();
                if (entry.getValue() > currentTime) {
                    count++;
                } else {
                    // 需要使用迭代器的 remove 方法，否则会 ConcurrentModificationException
                    iterator.remove();
                }
            }
            return count;
        }
    }

    // TODO 哈希表+双向链表
    // 优化思路：每次 countUnexpiredTokens 时遇到过期的 tokenId 可以直接删除，降低下一次循环的次数
    // 然而哈希表在遍历的过程中，可以使用迭代器，或者将 tokenId 组成一个链表，遍历链表头结点，然后
    // 再 map.remove(tokenId)

}
